package team.se.tms.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 反射工具类
 *
 * @author winkyle
 * @date 2018/11/18
 */
public class ReflectUtil {
    /**
     * 调用私有方法
     * 
     * @param clazz 目标类型
     * @param methodName 方法名
     * @param classes 参数类型数组
     * @param objects 参数数组
     * @return 方法的返回值
     * @create on 2018/11/18 by winkyle
     */
    public static Object invoke(final Class<?> clazz, final String methodName, final Class[] classes, final Object[] objects) {
        try {
            Method method = getMethod(clazz, methodName, classes);
            method.setAccessible(true);
            // 调用private方法的关键一句话
            return method.invoke(clazz.newInstance(), objects);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 调用私有方法
     *
     * @param clazz 目标类型
     * @param methodName 方法名
     * @param classes 参数类型数组
     * @return 方法的返回值
     * @create on 2018/11/18 by winkyle
     */
    public static Object invoke(final Class<?> clazz, final String methodName, final Class[] classes) {
        return invoke(clazz, methodName, classes, new Object[]{});
    }

    /**
     * 调用私有方法
     *
     * @param clazz 目标类型
     * @param methodName 方法名
     * @return 方法的返回值
     * @create on 2018/11/18 by winkyle
     */
    public static Object invoke(final Class<?> clazz, final String methodName) {
        return invoke(clazz, methodName, new Class[]{}, new Object[]{});
    }

    /**
     * 利用递归找一个类的指定方法，如果找不到，去父亲里面找直到最上层Object对象为止。
     * 
     * @param clazz 目标类型
     * @param methodName 方法名
     * @param classes 参数类型数组
     * @return 方法对象
     * @throws Exception 异常
     * @create on 2018/11/18 by winkyle
     */
    public static Method getMethod(Class clazz, String methodName, final Class[] classes) throws Exception {
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(methodName, classes);
        } catch (NoSuchMethodException e) {
            try {
                method = clazz.getMethod(methodName, classes);
            } catch (NoSuchMethodException ex) {
                if (clazz.getSuperclass() == null) {
                    return method;
                } else {
                    method = getMethod(clazz.getSuperclass(), methodName, classes);
                }
            }
        }
        return method;
    }


    /**
     * 利用反射获取指定对象的指定属性
     *
     * @param obj 目标对象
     * @param fieldName 目标属性
     * @return String 页面地址
     * @throws Exception 异常
     * @create on 2018/11/23 by johnny
     */
    public static Object getFieldValue(Object obj, String fieldName) {
        Object result = null;
        Field field = getField(obj, fieldName);
        if (field != null) {
            field.setAccessible(true);
            try {
                result = field.get(obj);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 利用反射获取指定对象里面的指定属性
     *
     * @param obj 目标对象
     * @param fieldName 目标属性
     * @return String 页面地址
     * @throws Exception 异常
     * @create on 2018/11/23 by johnny
     */
    public static Field getField(Object obj, String fieldName) {
        Field field = null;
        for (Class<?> clazz=obj.getClass(); clazz != Object.class; clazz=clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName);
                break;
            } catch (NoSuchFieldException e) {
                //这里不用做处理，子类没有该字段可能对应的父类有，都没有就返回null。
            }
        }
        return field;
    }


    /**
     * 利用反射设置指定对象的指定属性为指定的值
     * @param obj 目标对象
     * @param fieldName 目标属性
     * @param fieldValue 目标值
     * @create on 2018/11/23 by johnny
     */
    public static void setFieldValue(Object obj, String fieldName,
                                     String fieldValue) {
        Field field = getField(obj, fieldName);
        if (field != null) {
            try {
                field.setAccessible(true);
                field.set(obj, fieldValue);
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
